import { forwardRef, HttpException, Inject, Injectable } from '@nestjs/common'
import { CreateUserDto, PhoneCreateUserDto } from './dto/create-user.dto'
import { UserEntity } from './entities/user.entity'
import { InjectRepository } from '@nestjs/typeorm'
import { Between, EntityManager, Repository } from 'typeorm'
// import { JwtService } from '@nestjs/jwt'
import { LoginUserDto } from './dto/login-user.dto'
import { ModifyUserDto } from './dto/update-user.dto'
import { handleObjValue, maskEmail } from '@/utils'
import * as bcrypt from 'bcryptjs'
import { ModifyAvatarDto } from './dto/avatar.dto'
import { ModifyPassDto } from './dto/newPass.dto'
import { OrderEntity } from '../order/entities/order.entity'
import { CommentEntity } from '../comment/entities/comment.entity'
import { FavoriteEntity } from '../favorite/entities/favorite.entity'
import { UserCheckinEntity } from './entities/user-checkin.entity'
import { WalletLogService } from '../points/points.service'
import { VerificationService } from '../verification/verification.service'
// import { CryptoUtil } from '@/utils/crypto.util'
import { VerifyPhoneCodeDto } from './dto/verify-code.dto'
import regConfig from '@/config/reg.config'
import { ForgotPassDto } from './dto/forgotPass.dto'
import { walletType } from '@/mock'
// import { CaptchaService } from '../auth/captcha.service'

// 定义当月连续签到奖励规则
const STREAK_REWARDS = [
  { days: 5, reward: 15 },
  { days: 10, reward: 30 },
  { days: 15, reward: 50 }
]

@Injectable()
export class UserService {
  constructor(
    @InjectRepository(UserEntity)
    private readonly userRepository: Repository<UserEntity>,
    @InjectRepository(OrderEntity)
    private readonly orderRepository: Repository<OrderEntity>,
    @InjectRepository(CommentEntity)
    private readonly commentRepository: Repository<CommentEntity>,
    @InjectRepository(FavoriteEntity)
    private readonly favoriteRepository: Repository<FavoriteEntity>,
    @InjectRepository(UserCheckinEntity)
    private readonly userCheckinRepository: Repository<UserCheckinEntity>,
    private readonly entityManager: EntityManager, // 注入EntityManager，用于事务管理
    @Inject(forwardRef(() => WalletLogService))
    private readonly walletLogService: WalletLogService,
    @Inject(forwardRef(() => VerificationService))
    private readonly verificationService: VerificationService,
    // private readonly captchaService: CaptchaService
  ) { }

  // 注册账号
  async register(data: CreateUserDto) {
    if (data.account.length < 5 || data.account.length > 32) throw new HttpException("账号长度为5-32位", 400)
    if (!/^[a-zA-Z0-9_]+$/.test(data.account)) {
      throw new HttpException("账号只能包含字母、数字和下划线", 400)
    }
    if (data.password.length < 8 || data.password.length > 20) throw new HttpException("密码长度为8-20位", 400)
    if (!/(?=.*[A-Za-z])(?=.*\d)/.test(data.password)) {
      throw new HttpException("密码必须包含字母和数字", 400)
    }
    // if (data.nickname.length < 2 || data.nickname.length > 10) throw new HttpException("昵称长度为2-10位", 400)
    // if (!/^[a-zA-Z0-9\u4e00-\u9fa5]+$/.test(data.nickname)) {
    //   throw new HttpException("昵称只能包含字母、数字和中文", 400)
    // }
    if (!regConfig.email.test(data.email)) {
      throw new HttpException('请输入正确的邮箱', 400)
    }
    const isCodeValid = this.verificationService.verifyCode(data.email, data.code)
    if (!isCodeValid) throw new HttpException("邮箱验证码错误", 400)

    // 邮箱是否已被注册
    const existEmail = await this.userRepository.findOne({ where: { email: data.email } })
    if (existEmail) throw new HttpException("邮箱已被注册", 422)

    const exist = await this.userRepository.findOne({ where: { account: data.account } })
    if (exist) throw new HttpException("用户名已存在", 422)

    const temp = {
      ...data,
      role: data.role || 3,
      balance: 0,
      nickname: await this.generateRandomNickname(),
      create_time: Math.floor(Date.now() / 1000),
      update_time: Math.floor(Date.now() / 1000)
    }
    temp.password = await bcrypt.hash(data.password, 10)
    const savedUser = await this.userRepository.save(temp)
    // 记录注册日志
    await this.walletLogService.createTransaction(savedUser.id, walletType.REGISTER, 50)
    return savedUser
  }

  // 手机注册
  async registerByPhone(data: PhoneCreateUserDto) {
    if (!regConfig.phone.test(data.phone)) {
      throw new HttpException('请输入正确的手机号', 400)
    }
    if (data.password.length < 8 || data.password.length > 20) throw new HttpException("密码长度为8-20位", 400)
    if (!/(?=.*[A-Za-z])(?=.*\d)/.test(data.password)) {
      throw new HttpException("密码必须包含字母和数字", 400)
    }

    const isCodeValid = this.verificationService.verifyCode(data.phone, data.code)
    if (!isCodeValid) throw new HttpException("验证码错误", 400)

    const exist = await this.userRepository.findOne({ where: { phone: data.phone } })
    if (exist) throw new HttpException("手机号已存在", 422)

    const temp = {
      ...data,
      role: data.role || 3,
      balance: 0,
      nickname: await this.generateRandomNickname(),
      create_time: Math.floor(Date.now() / 1000),
      update_time: Math.floor(Date.now() / 1000)
    }
    temp.password = await bcrypt.hash(data.password, 10)
    const savedUser = await this.userRepository.save(temp)
    // 记录注册日志
    await this.walletLogService.createTransaction(savedUser.id, walletType.REGISTER, 50)
    return savedUser
  }

  // 生成随机昵称
  async generateRandomNickname() {
    const length = Math.floor(Math.random() * 9) + 2 // 2-10位
    const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\u4e00-\u9fa5'
    let nickname = ''
    for (let i = 0; i < length; i++) {
      const randomIndex = Math.floor(Math.random() * chars.length)
      nickname += chars.charAt(randomIndex)
    }
    // 检查昵称是否已存在
    const existNickname = await this.userRepository.findOne({ where: { nickname: nickname } })
    if (existNickname) {
      return this.generateRandomNickname()
    }
    return nickname
  }

  // 登录
  async login(data: LoginUserDto) {
    // 校验验证码
    // const isCaptchaValid = await this.captchaService.verifyIntelligentCaptcha(data.captchaParam || '')
    // if (!isCaptchaValid) throw new HttpException("验证码错误", 400)

    const accountTemp = await this.userRepository.findOne({ where: { account: data.account } })
    const phoneTemp = await this.userRepository.findOne({ where: { phone: data.account } })
    const emailTemp = await this.userRepository.findOne({ where: { email: data.account } })

    const userTemp = accountTemp || phoneTemp || emailTemp
    if (!userTemp) throw new HttpException("该用户不存在", 404)

    const isEqual = await bcrypt.compare(data.password, userTemp.password)
    if (!isEqual) throw new HttpException("密码错误", 400)

    // 后台+顾客角色
    if (Number(data?.pf) === 2 && userTemp.role === 3) throw new HttpException("您没有权限登录该系统", 403)
    return userTemp
  }

  // 手机快捷登录
  async loginByPhone(data: VerifyPhoneCodeDto) {
    if (!regConfig.phone.test(data.phone)) {
      throw new HttpException('请输入正确的手机号', 400)
    }
    if (!data.code) throw new HttpException("验证码必填", 400)
    if (!regConfig.IS_CODE.test(data.code)) throw new HttpException("验证码须为6位数字", 400)

    const temp = await this.userRepository.findOne({ where: { phone: data.phone } })
    if (!temp) throw new HttpException("手机号不存在", 404)

    const isCodeValid = this.verificationService.verifyCode(data.phone, data.code)
    if (!isCodeValid) throw new HttpException("验证码错误", 400)

    return temp
  }

  // 获取用户信息
  async getProfile(id: number) {
    const user = await this.userRepository.findOne({ where: { id } })
    if (!user) throw new HttpException("用户名不存在", 404)
    return user
  }

  // 修改用户信息
  async modifyUser(data: ModifyUserDto, userId: number) {
    const user = await this.userRepository.findOne({ where: { id: userId } })
    if (!user) throw new HttpException("用户名不存在", 404)

    const updateData = { data }
    const temp = handleObjValue(updateData)

    const tempData = await this.userRepository.update(user.id, { ...temp, update_time: Math.floor(Date.now() / 1000) })
    return tempData
  }

  // 修改头像
  async modifyAvatar(data: ModifyAvatarDto, userId: number) {
    const user = await this.userRepository.findOne({ where: { id: userId } })
    if (!user) throw new HttpException("用户名不存在", 404)

    const temp = handleObjValue(data)

    const tempData = await this.userRepository.update(user.id, { ...temp, update_time: Math.floor(Date.now() / 1000) })
    return tempData
  }

  // 修改密码
  async modifyPass(data: ModifyPassDto, userId: number) {
    const user = await this.userRepository.findOne({ where: { id: userId } })
    if (!user) throw new HttpException("用户名不存在", 404)

    if (!data.oldPass) throw new HttpException("旧密码必填", 400)
    if (!data.newPass) throw new HttpException("新密码必填", 400)
    if (!data.confirmPass) throw new HttpException("确认密码必填", 400)

    // 验证旧密码是否正确（通过哈希值比较）
    const isSamePassword = await bcrypt.compare(data.oldPass, user.password)
    if (!isSamePassword) {
      throw new HttpException("旧密码错误", 422)
    }

    // 验证新密码是否与旧密码相同
    const isSameNewPassword = await bcrypt.compare(data.newPass, user.password)
    if (isSameNewPassword) {
      throw new HttpException("新密码不能与旧密码相同", 422)
    }

    // 验证新密码是否与确认密码相同
    if (data.newPass !== data.confirmPass) {
      throw new HttpException("新密码与确认密码不匹配", 422)
    }

    // 加密新密码
    const hashPass = await bcrypt.hash(data.newPass, 10)

    const tempData = await this.userRepository.update(user.id, { password: hashPass, update_time: Math.floor(Date.now() / 1000) })
    return tempData
  }

  // 获取用户统计信息
  async getUserStat(userId: number) {

    const collect = await this.favoriteRepository.count({
      where: { user_id: userId }
    })
    const user = await this.userRepository.findOne({
      where: { id: userId }
    })
    const comment = await this.commentRepository.count({
      where: { user_id: userId }
    })

    return {
      collect,
      balance: user?.balance || 0,
      comment,
    }
  }

  // 获取用户当月签到统计信息
  async getMonthCheckinStat(userId: number) {
    const now = new Date()
    const currentMonth = now.getFullYear() * 100 + (now.getMonth() + 1)
    const currentDate = now.getDate()

    const monthCheckin = await this.userCheckinRepository.findOne({
      where: { userId, checkinMonth: currentMonth }
    })

    let checkinDays = ''
    let hasCheckedInToday = false

    if (monthCheckin) {
      checkinDays = monthCheckin.checkinDays || ''

      // 判断今天是否在已签到日期列表中
      if (checkinDays) {
        const checkedDaysArray = checkinDays.split(',').map(Number)
        hasCheckedInToday = checkedDaysArray.includes(currentDate)
      }
    }

    return {
      checkinDays: checkinDays,
      hasCheckedInToday: hasCheckedInToday ? 1 : 0, // 今日是否签到
      totalCheckinReward: monthCheckin?.totalCheckinReward || 0
    }
  }

  // 每日签到
  async checkin(userId: number) {
    return await this.entityManager.transaction(async manager => {
      const now = new Date()
      const currentDate = now.getDate()
      const currentMonth = now.getFullYear() * 100 + (now.getMonth() + 1)
      const nowTimestamp = Math.floor(now.getTime() / 1000)
      const baseReward = 10 // 固定签到奖励

      // 查询今日是否已签到
      const todayStartTimestamp = Math.floor(new Date(now.setHours(0, 0, 0, 0)).getTime() / 1000) // 今天凌晨时间戳
      const todayEndTimestamp = todayStartTimestamp + 24 * 60 * 60 - 1 // 今天23:59:59时间戳
      const todayCheckin = await manager.findOne(UserCheckinEntity, {
        where: {
          userId,
          checkin_time: Between(todayStartTimestamp, todayEndTimestamp) // 用时间范围判断当天签到
        }
      })
      if (todayCheckin) {
        throw new HttpException('今日已签到，明天再来吧～', 400)
      }

      // 查用户当月的签到统计记录（无则新建）
      let monthCheckin = await manager.findOne(UserCheckinEntity, {
        where: { userId, checkinMonth: currentMonth },
        order: { checkin_time: 'DESC' } // 取当月最新的签到记录（用于计算连续天数）
      })

      // 首次签到
      if (!monthCheckin) {
        // 计算累计积分（基础奖励 + 额外奖励）
        const firstTotalReward = baseReward + 0

        monthCheckin = manager.create(UserCheckinEntity, {
          userId,
          checkinMonth: currentMonth,
          checkinDays: currentDate.toString(),
          streakCount: 1,
          rewardCoin: baseReward,
          streakReward: 0,
          checkin_time: nowTimestamp,
          totalCheckinReward: firstTotalReward // 初始化累计积分
        })
      } else {
        // 连续签到
        const checkedDays = monthCheckin.checkinDays
          ? monthCheckin.checkinDays.split(',').map(Number)
          : []

        if (checkedDays.includes(currentDate)) {
          throw new HttpException('今日已签到，明天再来吧～', 400)
        }

        // 计算当月连续天数
        let newStreakCount = 1
        const lastCheckinDate = new Date(monthCheckin.checkin_time * 1000)
        const yesterdayDate = new Date()
        yesterdayDate.setDate(currentDate - 1) // 直接计算“昨天的日期”

        // 比较“上次签到的日期”是否等于“昨天的日期”（跨月也能正确判断）
        if (lastCheckinDate.getDate() === yesterdayDate.getDate() &&
          lastCheckinDate.getMonth() === yesterdayDate.getMonth()) {
          newStreakCount = monthCheckin.streakCount + 1
        }

        let streakReward = 0
        const rewardRule = STREAK_REWARDS.find(rule => rule.days === newStreakCount)
        if (rewardRule) {
          streakReward = rewardRule.reward
        }

        // 每签到15天重置连续天数（逻辑不变）
        if (newStreakCount % 15 === 0) {
          newStreakCount = 1
        }

        // 更新月度记录
        checkedDays.push(currentDate)
        checkedDays.sort((a, b) => a - b)
        const currentTotalReward = baseReward + streakReward // 本次签到总奖励

        monthCheckin.checkinDays = checkedDays.join(',')
        monthCheckin.streakCount = newStreakCount
        monthCheckin.rewardCoin = baseReward
        monthCheckin.streakReward = streakReward
        monthCheckin.checkin_time = nowTimestamp
        monthCheckin.totalCheckinReward += currentTotalReward // 累加累计积分
      }

      await manager.save(monthCheckin)

      // 更新用户余额
      const user = await manager.findOne(UserEntity, { where: { id: userId } })
      if (!user) {
        throw new HttpException('用户不存在', 404)
      }
      const totalReward = baseReward + monthCheckin.streakReward
      // user.balance += totalReward
      // 记录签到日志
      await this.walletLogService.createTransaction(userId, walletType.CHECK_IN, totalReward)
      user.update_time = nowTimestamp
      await manager.save(user)

      const messages = [`签到成功！获得${baseReward}饭币基础奖励。`]
      if (monthCheckin.streakReward > 0) {
        messages.push(`太棒了！当月连续签到${monthCheckin.streakCount}天，额外奖励${monthCheckin.streakReward}饭币！`)
      }
      messages.push(`当前余额${user.balance}饭币，累计签到获得${monthCheckin.totalCheckinReward}饭币。`)

      return {
        message: messages.join(' '),
        currentCoin: user.balance,
        checkinDays: monthCheckin.checkinDays,
        totalCheckinReward: monthCheckin.totalCheckinReward,
        checkinMonth: monthCheckin.checkinMonth
      }
    })
  }

  // 根据邮箱查询用户
  async findByEmail(plainEmail: string) {
    if (!plainEmail) return null
    return this.userRepository.findOne({
      where: { email: plainEmail }
    })
  }

  // 根据ID查询用户
  async findById(id: number) {
    const user = await this.userRepository.findOne({ where: { id } })
    if (!user) {
      throw new HttpException('用户不存在', 404)
    }
    return user
  }

  // 更新用户邮箱
  async updateEmailDirectly(userId: number, newEmail: string) {
    // 先查询用户是否存在
    const user = await this.findById(userId)

    // 更新邮箱
    user.email = newEmail
    user.update_time = Math.floor(Date.now() / 1000)
    return this.userRepository.save(user)
  }

  // 更新用户邮箱
  async updateEmail(userId: number, newEmail: string, code: string) {
    if (!regConfig.email.test(newEmail)) {
      throw new HttpException('请输入正确的邮箱格式', 400)
    }
    // 验证验证码有效性
    const isCodeValid = this.verificationService.verifyCode(newEmail, code)
    if (!isCodeValid) {
      throw new HttpException('验证码验证失败', 400)
    }

    // 检查邮箱是否已被其他用户使用
    const existingUser = await this.findByEmail(newEmail)
    if (existingUser && existingUser.id !== userId) {
      throw new HttpException('该邮箱已被其他用户绑定', 409)
    }

    // 邮箱更新
    try {
      const updatedUser = await this.updateEmailDirectly(userId, newEmail)
      return {
        success: true,
        message: '邮箱更新成功',
        // data: {
        //   id: updatedUser.id,
        //   email: maskEmail(updatedUser.email),
        // },
      }
    } catch (error) {
      console.error('邮箱更新失败：', error.message)
      throw new HttpException('更新邮箱失败，请稍后重试', 500)
    }
  }

  // 重置密码
  async resetPassword(data: ForgotPassDto) {
    // 1邮箱 2手机号
    const whereCondition = data.type === 1
      ? { email: data.account }
      : { phone: data.account }

    const user = await this.userRepository.findOne({ where: whereCondition })
    if (!user) {
      throw new HttpException('用户不存在', 404)
    }

    // 验证验证码
    const isCodeValid = await this.verificationService.verifyCode(
      data.account,
      data.code
    )
    if (!isCodeValid) {
      throw new HttpException('验证码无效或已过期', 400)
    }

    // 校验新密码是否与旧密码相同
    const isSameAsOld = await bcrypt.compare(data.newPass, user.password)
    if (isSameAsOld) {
      throw new HttpException('新密码不能与旧密码相同', 400)
    }

    // 更新密码
    const hashedPassword = await bcrypt.hash(data.newPass, 10)
    await this.userRepository.update(user.id, { password: hashedPassword })

    return {
      success: true,
      message: '密码重置成功'
    }
  }
}
